import Dep from "./observe/dep";
import { observe } from "./observe/index";
import Watcher from "./observe/watcher";

export function initState(vm) {
  const opts = vm.$options; //获取所有的选项，props,data,watch.computed等等
  if (opts.data) {
    initData(vm);
  }
  if (opts.computed) {
    initComputed(vm)
  }
  if (opts.watch) {
    initWatch(vm)
  }
}
function proxy(vm,target,key){
  Object.defineProperty(vm,key,{
    get(){
      return vm[target][key]
    },
    set(newValue){
      vm[target][key] = newValue
    }
  })
}
function initData(vm) {
  let data = vm.$options.data; //data可能是对象或者函数
  data = typeof data === "function" ? data.call(vm) : data;

  vm._data = data
  // 对数据进行劫持
  observe(data)

  // 将vm._data用vm作数据代理
  for(let key in data){
    proxy(vm,'_data',key)
  }
}
function initComputed(vm){
  const computed = vm.$options.computed
  const watchers = vm._computedWatchers={}
  for(let key in computed){
    let userDef = computed[key]
    const fn = typeof userDef === 'function'? userDef:userDef.get
    watchers[key] = new Watcher(vm,fn,{lazy:true})

   defineComputed(vm,key,userDef)
  }
}
function defineComputed(target,key,userDef){
   const getter = typeof userDef === 'function'? userDef:userDef.get
   const setter = userDef.set|| (()=>{})

  //  通过实例拿到对应的属性
  Object.defineProperty(target,key,{
    get:createComputedGetter(key),
    set:setter
  })
}
// 实现computed缓存功能
function createComputedGetter(key){

  return function(){
    const watcher =  this._computedWatchers[key] //获取到对应属性的watcher
    if (watcher.dirty) {
      watcher.evaluate()
    }
    if (Dep.target) {//计算属性出栈后，还要渲染watcher
      watcher.depend()
    }
    return watcher.value
  }
}

function initWatch(vm){
  let watch = vm.$options.watch
  for(let key in watch){ 
    const handler = watch[key] //key可能是字符串 数组 函数
    if (Array.isArray(handler)) {
      for (let i = 0; i < handler.length; i++) {
          createWatcher(vm,key,handler[i])        
      }
    }else{
      createWatcher(vm,key,handler)        

    }

  }
}
function createWatcher(vm,key,handler){
  if (typeof handler ==='string') {
    handler = vm[handler]
  }
  return vm.$watch(key,handler)
}
